package com.yupi.yupicturebackend.controller;

import com.yupi.yupicturebackend.annotation.AuthCheck;
import com.yupi.yupicturebackend.common.BaseResponse;
import com.yupi.yupicturebackend.common.ResultUtils;
import com.yupi.yupicturebackend.constant.UserConstant;
import com.yupi.yupicturebackend.exception.ErrorCode;
import com.yupi.yupicturebackend.exception.ThrowUtils;
import com.yupi.yupicturebackend.model.dto.blockchain.*;
import com.yupi.yupicturebackend.model.entity.NFTAsset;
import com.yupi.yupicturebackend.model.entity.User;
import com.yupi.yupicturebackend.service.NFTAssetService;
import com.yupi.yupicturebackend.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * NFT资产控制器
 *
 * @author yupi
 */
@Slf4j
@RestController
@RequestMapping("/nft")
public class NFTAssetController {

    @Resource
    private NFTAssetService nftAssetService;

    @Resource
    private UserService userService;

    /**
     * 铸造NFT
     *
     * @param request 铸造请求
     * @param httpRequest HTTP请求
     * @return 铸造结果
     */
    @PostMapping("/mint")
    public BaseResponse<NFTMintResult> mintNFT(@RequestBody MintNFTRequest request,
                                             HttpServletRequest httpRequest) {
        ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(request.getImageUrl() == null || request.getImageUrl().trim().isEmpty(),
            ErrorCode.PARAMS_ERROR, "图片URL不能为空");
        ThrowUtils.throwIf(request.getNftConfig() == null, ErrorCode.PARAMS_ERROR, "NFT配置不能为空");
        
        User loginUser = userService.getLoginUser(httpRequest);
        NFTMintResult result = nftAssetService.mintNFT(request.getImageUrl(), request.getNftConfig(), loginUser.getId());
        
        return ResultUtils.success(result);
    }

    /**
     * 批量铸造NFT
     *
     * @param request 批量铸造请求
     * @param httpRequest HTTP请求
     * @return 铸造结果列表
     */
    @PostMapping("/batch-mint")
    public BaseResponse<List<NFTMintResult>> batchMintNFTs(@RequestBody BatchMintNFTRequest request,
                                                         HttpServletRequest httpRequest) {
        ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(request.getImageUrls() == null || request.getImageUrls().isEmpty(),
            ErrorCode.PARAMS_ERROR, "图片URL列表不能为空");
        ThrowUtils.throwIf(request.getImageUrls().size() > 10,
            ErrorCode.PARAMS_ERROR, "批量铸造数量不能超过10个");
        ThrowUtils.throwIf(request.getNftConfig() == null, ErrorCode.PARAMS_ERROR, "NFT配置不能为空");
        
        User loginUser = userService.getLoginUser(httpRequest);
        List<NFTMintResult> results = nftAssetService.batchMintNFTs(
            request.getImageUrls(), request.getNftConfig(), loginUser.getId());
        
        return ResultUtils.success(results);
    }

    /**
     * 交易NFT
     *
     * @param request 交易请求
     * @param httpRequest HTTP请求
     * @return 交易结果
     */
    @PostMapping("/trade")
    public BaseResponse<NFTTradeResult> tradeNFT(@RequestBody TradeNFTRequest request,
                                               HttpServletRequest httpRequest) {
        ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(request.getTradeConfig() == null, ErrorCode.PARAMS_ERROR, "交易配置不能为空");
        
        User loginUser = userService.getLoginUser(httpRequest);
        NFTTradeResult result = nftAssetService.tradeNFT(request.getTradeConfig(), loginUser.getId());
        
        return ResultUtils.success(result);
    }

    /**
     * 获取用户NFT列表
     *
     * @param limit 限制数量
     * @param httpRequest HTTP请求
     * @return NFT列表
     */
    @GetMapping("/my-nfts")
    public BaseResponse<List<NFTAsset>> getUserNFTs(@RequestParam(defaultValue = "20") Integer limit,
                                                  HttpServletRequest httpRequest) {
        User loginUser = userService.getLoginUser(httpRequest);
        List<NFTAsset> nfts = nftAssetService.getUserNFTs(loginUser.getId(), limit);
        
        return ResultUtils.success(nfts);
    }

    /**
     * 获取NFT详情
     *
     * @param nftId NFT ID
     * @return NFT详情
     */
    @GetMapping("/{nftId}")
    public BaseResponse<NFTAsset> getNFTDetail(@PathVariable Long nftId) {
        ThrowUtils.throwIf(nftId == null || nftId <= 0, ErrorCode.PARAMS_ERROR, "NFT ID无效");
        
        NFTAsset nft = nftAssetService.getById(nftId);
        ThrowUtils.throwIf(nft == null, ErrorCode.NOT_FOUND_ERROR, "NFT不存在");
        
        // 增加浏览量
        nftAssetService.incrementViewCount(nftId);
        
        return ResultUtils.success(nft);
    }

    /**
     * 搜索NFT
     *
     * @param keyword 关键词
     * @param limit 限制数量
     * @return NFT列表
     */
    @GetMapping("/search")
    public BaseResponse<List<NFTAsset>> searchNFTs(@RequestParam String keyword,
                                                 @RequestParam(defaultValue = "20") Integer limit) {
        ThrowUtils.throwIf(keyword == null || keyword.trim().isEmpty(),
            ErrorCode.PARAMS_ERROR, "搜索关键词不能为空");
        
        List<NFTAsset> nfts = nftAssetService.searchNFTs(keyword, limit);
        
        return ResultUtils.success(nfts);
    }

    /**
     * 按价格范围查询NFT
     *
     * @param minPrice 最低价格
     * @param maxPrice 最高价格
     * @param currency 货币单位
     * @param limit 限制数量
     * @return NFT列表
     */
    @GetMapping("/price-range")
    public BaseResponse<List<NFTAsset>> getNFTsByPriceRange(@RequestParam BigDecimal minPrice,
                                                          @RequestParam BigDecimal maxPrice,
                                                          @RequestParam(defaultValue = "ETH") String currency,
                                                          @RequestParam(defaultValue = "20") Integer limit) {
        ThrowUtils.throwIf(minPrice == null || maxPrice == null, ErrorCode.PARAMS_ERROR, "价格范围不能为空");
        ThrowUtils.throwIf(minPrice.compareTo(maxPrice) > 0, ErrorCode.PARAMS_ERROR, "最低价格不能大于最高价格");
        
        List<NFTAsset> nfts = nftAssetService.getNFTsByPriceRange(minPrice, maxPrice, currency, limit);
        
        return ResultUtils.success(nfts);
    }

    /**
     * 获取热门NFT
     *
     * @param limit 限制数量
     * @return 热门NFT列表
     */
    @GetMapping("/popular")
    public BaseResponse<List<NFTAsset>> getPopularNFTs(@RequestParam(defaultValue = "20") Integer limit) {
        List<NFTAsset> nfts = nftAssetService.getPopularNFTs(limit);
        
        return ResultUtils.success(nfts);
    }

    /**
     * 获取最新铸造的NFT
     *
     * @param limit 限制数量
     * @return 最新NFT列表
     */
    @GetMapping("/latest")
    public BaseResponse<List<NFTAsset>> getLatestMintedNFTs(@RequestParam(defaultValue = "20") Integer limit) {
        List<NFTAsset> nfts = nftAssetService.getLatestMintedNFTs(limit);
        
        return ResultUtils.success(nfts);
    }

    /**
     * 按创作者查询NFT
     *
     * @param creator 创作者
     * @param limit 限制数量
     * @return NFT列表
     */
    @GetMapping("/creator/{creator}")
    public BaseResponse<List<NFTAsset>> getNFTsByCreator(@PathVariable String creator,
                                                       @RequestParam(defaultValue = "20") Integer limit) {
        ThrowUtils.throwIf(creator == null || creator.trim().isEmpty(),
            ErrorCode.PARAMS_ERROR, "创作者不能为空");
        
        List<NFTAsset> nfts = nftAssetService.getNFTsByCreator(creator, limit);
        
        return ResultUtils.success(nfts);
    }

    /**
     * 按集合查询NFT
     *
     * @param collection 集合名称
     * @param limit 限制数量
     * @return NFT列表
     */
    @GetMapping("/collection/{collection}")
    public BaseResponse<List<NFTAsset>> getNFTsByCollection(@PathVariable String collection,
                                                          @RequestParam(defaultValue = "20") Integer limit) {
        ThrowUtils.throwIf(collection == null || collection.trim().isEmpty(),
            ErrorCode.PARAMS_ERROR, "集合名称不能为空");
        
        List<NFTAsset> nfts = nftAssetService.getNFTsByCollection(collection, limit);
        
        return ResultUtils.success(nfts);
    }

    /**
     * 点赞NFT
     *
     * @param nftId NFT ID
     * @param httpRequest HTTP请求
     * @return 是否成功
     */
    @PostMapping("/{nftId}/like")
    public BaseResponse<Boolean> likeNFT(@PathVariable Long nftId,
                                       HttpServletRequest httpRequest) {
        ThrowUtils.throwIf(nftId == null || nftId <= 0, ErrorCode.PARAMS_ERROR, "NFT ID无效");
        
        User loginUser = userService.getLoginUser(httpRequest);
        boolean success = nftAssetService.likeNFT(nftId, loginUser.getId());
        
        return ResultUtils.success(success);
    }

    /**
     * 更新NFT价格
     *
     * @param nftId NFT ID
     * @param request 价格更新请求
     * @param httpRequest HTTP请求
     * @return 是否成功
     */
    @PostMapping("/{nftId}/price")
    public BaseResponse<Boolean> updateNFTPrice(@PathVariable Long nftId,
                                              @RequestBody UpdatePriceRequest request,
                                              HttpServletRequest httpRequest) {
        ThrowUtils.throwIf(nftId == null || nftId <= 0, ErrorCode.PARAMS_ERROR, "NFT ID无效");
        ThrowUtils.throwIf(request == null || request.getPrice() == null,
            ErrorCode.PARAMS_ERROR, "价格不能为空");
        
        User loginUser = userService.getLoginUser(httpRequest);
        boolean success = nftAssetService.updateNFTPrice(
            nftId, request.getPrice(), request.getCurrency(), loginUser.getId());
        
        return ResultUtils.success(success);
    }

    /**
     * 设置NFT可交易状态
     *
     * @param nftId NFT ID
     * @param request 交易状态请求
     * @param httpRequest HTTP请求
     * @return 是否成功
     */
    @PostMapping("/{nftId}/tradeable")
    public BaseResponse<Boolean> setNFTTradeable(@PathVariable Long nftId,
                                               @RequestBody TradeableRequest request,
                                               HttpServletRequest httpRequest) {
        ThrowUtils.throwIf(nftId == null || nftId <= 0, ErrorCode.PARAMS_ERROR, "NFT ID无效");
        ThrowUtils.throwIf(request == null || request.getTradeable() == null,
            ErrorCode.PARAMS_ERROR, "交易状态不能为空");
        
        User loginUser = userService.getLoginUser(httpRequest);
        boolean success = nftAssetService.setNFTTradeable(nftId, request.getTradeable(), loginUser.getId());
        
        return ResultUtils.success(success);
    }

    /**
     * 获取推荐NFT
     *
     * @param limit 限制数量
     * @param httpRequest HTTP请求
     * @return 推荐NFT列表
     */
    @GetMapping("/recommended")
    public BaseResponse<List<NFTAsset>> getRecommendedNFTs(@RequestParam(defaultValue = "20") Integer limit,
                                                         HttpServletRequest httpRequest) {
        User loginUser = userService.getLoginUser(httpRequest);
        List<NFTAsset> nfts = nftAssetService.getRecommendedNFTs(loginUser.getId(), limit);
        
        return ResultUtils.success(nfts);
    }

    /**
     * 获取NFT统计信息
     *
     * @param httpRequest HTTP请求
     * @return 统计信息
     */
    @GetMapping("/statistics")
    public BaseResponse<Map<String, Object>> getNFTStatistics(HttpServletRequest httpRequest) {
        User loginUser = userService.getLoginUser(httpRequest);
        Map<String, Object> statistics = nftAssetService.getNFTStatistics(loginUser.getId());
        
        return ResultUtils.success(statistics);
    }

    /**
     * 获取全局NFT统计信息（管理员）
     *
     * @return 全局统计信息
     */
    @GetMapping("/global-statistics")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Map<String, Object>> getGlobalNFTStatistics() {
        Map<String, Object> statistics = nftAssetService.getNFTStatistics(null);
        
        return ResultUtils.success(statistics);
    }

    // ==================== 请求DTO类 ====================

    /**
     * 铸造NFT请求
     */
    public static class MintNFTRequest {
        private String imageUrl;
        private NFTConfig nftConfig;
        
        public String getImageUrl() { return imageUrl; }
        public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; }
        public NFTConfig getNftConfig() { return nftConfig; }
        public void setNftConfig(NFTConfig nftConfig) { this.nftConfig = nftConfig; }
    }

    /**
     * 批量铸造NFT请求
     */
    public static class BatchMintNFTRequest {
        private List<String> imageUrls;
        private NFTConfig nftConfig;
        
        public List<String> getImageUrls() { return imageUrls; }
        public void setImageUrls(List<String> imageUrls) { this.imageUrls = imageUrls; }
        public NFTConfig getNftConfig() { return nftConfig; }
        public void setNftConfig(NFTConfig nftConfig) { this.nftConfig = nftConfig; }
    }

    /**
     * 交易NFT请求
     */
    public static class TradeNFTRequest {
        private NFTTradeConfig tradeConfig;
        
        public NFTTradeConfig getTradeConfig() { return tradeConfig; }
        public void setTradeConfig(NFTTradeConfig tradeConfig) { this.tradeConfig = tradeConfig; }
    }

    /**
     * 价格更新请求
     */
    public static class UpdatePriceRequest {
        private BigDecimal price;
        private String currency;
        
        public BigDecimal getPrice() { return price; }
        public void setPrice(BigDecimal price) { this.price = price; }
        public String getCurrency() { return currency; }
        public void setCurrency(String currency) { this.currency = currency; }
    }

    /**
     * 交易状态请求
     */
    public static class TradeableRequest {
        private Boolean tradeable;
        
        public Boolean getTradeable() { return tradeable; }
        public void setTradeable(Boolean tradeable) { this.tradeable = tradeable; }
    }
}
